package main

import (
	"fmt"
	"sync"
	"sync/atomic"
	"time"
)

/*
题目 ：编写一个Go程序，定义一个函数，该函数接收一个整数指针作为参数，在函数内部将该指针指向的值增加10，
然后在主函数中调用该函数并输出修改后的值。考察点 ：指针的使用、值传递与引用传递的区别。
*/

func taskOne(a *int) {
	*a += 10
}

/*
题目 ：实现一个函数，接收一个整数切片的指针，将切片中的每个元素乘以2。
考察点 ：指针运算、切片操作。
*/
func taskTwo(s *[]int) {
	if s == nil || *s == nil {
		return
	}
	for i := range *s { //for i, v := range (*s)
		(*s)[i] *= 2
	}
}

/*
	✅Goroutine
题目 ：编写一个程序，使用 go 关键字启动两个协程，一个协程打印从1到10的奇数，另一个协程打印从2到10的偶数。
考察点 ： go 关键字的使用、协程的并发执行。
*/

var wg sync.WaitGroup

func taskThree() {
	wg.Add(1)
	go func() {
		defer wg.Done()
		for i := 1; i <= 10; i += 2 {
			fmt.Println(i)
		}
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		for i := 2; i <= 10; i += 2 {
			fmt.Println(i)
		}
	}()

}

/*
题目 ：设计一个任务调度器，接收一组任务（可以用函数表示），并使用协程并发执行这些任务，同时统计每个任务的执行时间。
考察点 ：协程原理、并发任务调度。
*/
var taskListWg sync.WaitGroup

// TaskStat 保存单个任务的耗时
type TaskStat struct {
	ID   int
	Cost time.Duration
}

// runTask 启动一个 goroutine 去执行 task，完成后把耗时发送到 resultCh
func runTask(id int, task func(), wg *sync.WaitGroup, resultCh chan<- TaskStat) {
	wg.Add(1)
	go func() {
		defer wg.Done()
		start := time.Now()
		task() // 真正执行任务
		resultCh <- TaskStat{id, time.Since(start)}
	}()
}
func TaskFour(taskList []func()) {

	// 2. 并发调度
	var wg sync.WaitGroup
	resultCh := make(chan TaskStat, len(taskList))

	for i, t := range taskList {
		runTask(i, t, &wg, resultCh)
	}
	// 3. 等待所有任务完成，然后关闭 channel
	go func() {
		wg.Wait()
		close(resultCh)
	}()

	// 4. 收集统计结果
	for stat := range resultCh {
		fmt.Printf("Task %d finished in %v\n", stat.ID, stat.Cost)
	}
}

/*✅面向对象
题目 ：定义一个 Shape 接口，包含 Area() 和 Perimeter() 两个方法。然后创建 Rectangle 和 Circle 结构体，
实现 Shape 接口。在主函数中，创建这两个结构体的实例，并调用它们的 Area() 和 Perimeter() 方法。
考察点 ：接口的定义与实现、面向对象编程风格。
*/

type Shape interface {
	Area() float64
	Perimeter() float64
}

type Rectangle struct {
	Width  float64
	Height float64
}
type Circle struct {
	Radius float64
}

// 3. 矩形实现 Shape 接口  就是Rectangle 实例实现Area方法
func (r Rectangle) Area() float64 {
	return r.Width * r.Height
}

func (r Rectangle) Perimeter() float64 {
	return 2 * (r.Width + r.Height)
}

func (r Circle) Area() float64 {
	return r.Radius * r.Radius
}

func (r Circle) Perimeter() float64 {
	return 4 * r.Radius
}

/*
题目 ：使用组合的方式创建一个 Person 结构体，包含 Name 和 Age 字段，再创建一个 Employee 结构体，
组合 Person 结构体并添加 EmployeeID 字段。为 Employee 结构体实现一个 PrintInfo() 方法，输出员工的信息。
考察点 ：组合的使用、方法接收者。*/

type Person struct {
	Name string
	Age  int
}
type Employee struct {
	Person
	EmployeeID int
}

func (e *Employee) PrintInfo() {
	fmt.Printf("Name: %s, Age: %d, EmployeeID: %d\n", e.Name, e.Age, e.EmployeeID)
}

/*
✅Channel
题目 ：编写一个程序，使用通道实现两个协程之间的通信。一个协程生成从1到10的整数，并将这些整数发送到通道中，另一个协程从通道中接收这些整数并打印出来。
考察点 ：通道的基本使用、协程间通信。
题目 ：实现一个带有缓冲的通道，生产者协程向通道中发送100个整数，消费者协程从通道中接收这些整数并打印。
考察点 ：通道的缓冲机制。
*/

func producer(ch chan<- int, total int) {
	for i := 1; i <= total; i++ {
		ch <- i
	}
	close(ch)
}

func consumer(ch <-chan int) {
	for v := range ch {
		fmt.Println("recv:", v)
	}
}

/*
✅锁机制
题目 ：编写一个程序，使用 sync.Mutex 来保护一个共享的计数器。启动10个协程，每个协程对计数器进行1000次递增操作，最后输出计数器的值。
考察点 ： sync.Mutex 的使用、并发数据安全。
*/

var mu sync.Mutex

func lockCounter(count int) int {

	// 在循环外一次性添加所有等待项

	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for j := 0; j < 1000; j++ {
				mu.Lock()
				count++
				mu.Unlock()
			}
		}()
	}

	wg.Wait()
	return count
}

/*
题目 ：使用原子操作（ sync/atomic 包）实现一个无锁的计数器。启动10个协程，每个协程对计数器进行1000次递增操作，最后输出计数器的值。
考察点 ：原子操作、并发数据安全。
*/

func lockCounter2(counter int64) int64 {

	// 在循环外一次性添加所有等待项

	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for j := 0; j < 1000; j++ {
				atomic.AddInt64(&counter, 1) // 原子递增
			}
		}()
	}

	wg.Wait()
	return counter
}